package se.webbzon.boltzmann.game.object.action;

import java.awt.Color;
import java.util.HashMap;
import java.util.Map;

import se.webbzon.boltzmann.environment.AbstractEnvironment;
import se.webbzon.boltzmann.game.event.GameEventEnum;
import se.webbzon.boltzmann.game.object.dialogue.DialogueBackground;
import se.webbzon.boltzmann.game.object.dialogue.layout.DefaultChoiceDialogueLayout;
import se.webbzon.boltzmann.game.object.dialogue.layout.DefaultSimpleDialogueLayout;
import se.webbzon.boltzmann.game.object.item.GameItemContainer;
import se.webbzon.boltzmann.game.object.player.AbstractPlayerCharacter;
import se.webbzon.boltzmann.game.sequence.Sequence;
import se.webbzon.boltzmann.game.sequence.SequenceListener;
import se.webbzon.boltzmann.game.sequence.SequenceNode;
import se.webbzon.boltzmann.game.sequence.builder.AbstractSequenceBinding;
import se.webbzon.boltzmann.game.sequence.builder.SequenceBuilder;
import se.webbzon.boltzmann.game.sequence.builder.SoftSequenceBinding;
import se.webbzon.boltzmann.game.sequence.builder.assignment.AssignmentRow;
import se.webbzon.boltzmann.game.sequence.builder.condition.ConditionEnum;
import se.webbzon.boltzmann.game.sequence.builder.condition.ConditionRow;
import se.webbzon.boltzmann.game.sequence.builder.dialogue.ChoiceDialogueRow;
import se.webbzon.boltzmann.game.sequence.builder.dialogue.SimpleDialogueRow;
import se.webbzon.boltzmann.game.sequence.builder.event.GameEventRow;
import se.webbzon.boltzmann.item.AbstractItem;
import se.webbzon.boltzmann.item.ItemGroup;
import se.webbzon.oschi01.worldarea.WorldArea;
import se.webbzon.oschi01.worldeditor.DeflatableWorldObject;
import se.webbzon.oschi01.worldeditor.WorldObjectDeflation;
import se.webbzon.oschi01.worldobject.WorldObject;

public class ShopAction extends AbstractAction<GameItemContainer> implements DeflatableWorldObject {
	
	// The name of the deflatable world object
	public static final String worldObjectName = "shopAction";
	
	// The texts dialogues
	private static final String choiceText = "The price of this#<K>@1</>#is <D>@price</> <K>silver coins</>.";
	private static final String noSpaceText = "You do not have enough space#to store this item.";
	private static final String tooExpensiveText = "You do not have enough silver#coins to buy this item.";
	
	// The price of the item
	private String price;
	
	// The sequence node associated with this sequence action 
	// (only available when debug mode is false)
	private SequenceNode sequenceNode;
	
	/*============================================================
	Constructors
	============================================================*/

	/** Creates a new sequence action. **/
	public ShopAction(	AbstractEnvironment env,
						GameItemContainer parent, 
						String price, boolean frontOnly, double range) {
		super(0, env, parent, Color.yellow, frontOnly, range);
		this.price = price;
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Returns the price of the product. **/
	public String getPrice() {
		return price;
	}
	
	/** Sets the price of this product. **/
	public void setPrice(String price) {
		this.price = price;
	}
	
	@Override public void onCreate(WorldArea world) {
		super.onCreate(world);
		if (!getEnvironment().isDebugMode())
			sequenceNode = createSequenceNode(world);
	}
	
	@Override public void onDestroy(WorldArea world) {
		super.onDestroy(world);
		sequenceNode = null;
	}
	
	@Override public void onActionBegin(GameItemContainer parent,
										AbstractPlayerCharacter player) {
		player.setFacing(this);
		Object blocker = player.containBlocker();
		
		Map<String,WorldObject> bindings = new HashMap<String,WorldObject>();
		bindings.put(AbstractSequenceBinding.PARENT, parent);
		bindings.put(AbstractSequenceBinding.PLAYER, player);

		Sequence sequence = sequenceNode.getSequence();
		sequence.addListener(new SequenceListenerImpl(player,blocker));
		sequence.begin(player.getPlayer().getInput(), sequenceNode, bindings);
	}

	@Override public String getName() {
		return worldObjectName;
	}

	@Override public WorldObjectDeflation getDeflation() {
		return new ShopActionDeflation(0,this);
	}
	
	/*============================================================
	Private Methods
	============================================================*/
	
	/** Creates a new sequence node for this shop action. **/
	private SequenceNode createSequenceNode(WorldArea world) {
		GameItemContainer container = (GameItemContainer) getParent();
		if (container == null)
			return null;
		AbstractItem item = container.getItem();
		if (item == null)
			return null;
		
		SequenceBuilder builder = new SequenceBuilder(getEnvironment());
		DefaultChoiceDialogueLayout choiceLayout = new DefaultChoiceDialogueLayout();
		DefaultSimpleDialogueLayout simpleLayout = new DefaultSimpleDialogueLayout();
		String choiceText = ShopAction.choiceText.replaceFirst("@1", item.getName());
		
		/** Add rows **/
		AssignmentRow base = new AssignmentRow(builder, "@base_price", "" + item.getBaseValue());
		AssignmentRow value = new AssignmentRow(builder, "@price", price);
		ChoiceDialogueRow choice = new ChoiceDialogueRow(builder,choiceLayout,DialogueBackground.INFO,choiceText);
		choice.setBinding(new SoftSequenceBinding(AbstractSequenceBinding.PARENT));
		choice.addChoice("Buy");
		choice.addChoice("Don't buy");
		ConditionRow canStore = new ConditionRow(builder, ConditionEnum.canStore);
		ConditionRow hasSilver = new ConditionRow(builder, ConditionEnum.isGreaterOrEqual, "@coins", "@price");
		SimpleDialogueRow noSpace = new SimpleDialogueRow(builder,simpleLayout,DialogueBackground.INFO,noSpaceText);
		noSpace.setBinding(new SoftSequenceBinding(AbstractSequenceBinding.PARENT));
		AssignmentRow pay = new AssignmentRow(builder, "@coins", "- @coins @price");
		new GameEventRow(builder,GameEventEnum.giveItem,new String[] {"" + ItemGroup.instance().getId(item)});
		SimpleDialogueRow tooExpensive = new SimpleDialogueRow(builder,simpleLayout,DialogueBackground.INFO,tooExpensiveText);
		tooExpensive.setBinding(new SoftSequenceBinding(AbstractSequenceBinding.PARENT));
		
		/** Link rows **/
		base.addLink(1);
		value.addLink(2);
		choice.addLink(3);
		canStore.setLink(0,4);
		canStore.setLink(1,5);
		hasSilver.setLink(0,6);
		hasSilver.setLink(1,8);
		pay.addLink(7);
		return builder.compile(world);
	}
	
	/*============================================================
	Private Classes
	============================================================*/
	
	/** An implementation of a sequence listener. **/
	private final class SequenceListenerImpl implements SequenceListener {
		
		// The player associated with this sequence listener
		private final AbstractPlayerCharacter player;
		
		// The player blocker
		private final Object playerBlocker;
		
		/*============================================================
		Constructors
		============================================================*/
		
		public SequenceListenerImpl(AbstractPlayerCharacter player,
									Object playerBlocker) {
			this.player = player;
			this.playerBlocker = playerBlocker;
		}
		
		/*============================================================
		Public Methods
		============================================================*/
		
		@Override public void onSequenceBegin(Sequence sequence) {};

		@Override public void onSequenceEnd(Sequence sequence) {
			sequence.removeListener(this);
			player.releaseBlocker(playerBlocker);
			setActive(true);
		}
		
	}

}
